package graphBuilder;

import Shared.Utils;

import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
import org.jgrapht.graph.WeightedPseudograph;

import Shared.MapPosition;
import Shared.Utils;

public class PointToGraph 
{
	private static final double THRESHOLD = 15;
	// load file
	private String bin_file_name = "thoralf.bin";
	private String graph_bin_filename = "graph.bin";
	private String pseudograph_bin_filename = "pseudograph.bin";
	private ArrayList<Point[]> list = null;

	public PointToGraph()
	{
		loadGraph();
		Utils.disp("Points loaded");
		
		//this.generateWeightedSimpleGraph();
		this.generateWeightedPseudoGraph();

		// SimpleWeightedGraph
		// addEdge, addEdge, addVertex, containsEdge, containsEdge,
		// containsVertex, edgeSet, edgesOf, getAllEdges, getEdge,
		// getEdgeFactory, getEdgeSource, getEdgeTarget, getEdgeWeight,
		// removeAllEdges, removeAllEdges, removeAllVertices, removeEdge,
		// removeEdge, removeVertex, vertexSet
		
	}
	private void generateWeightedPseudoGraph()
	{
		WeightedPseudograph<MapPosition,DefaultWeightedEdge> graph = new WeightedPseudograph<MapPosition,DefaultWeightedEdge>(DefaultWeightedEdge.class);
		
		// iterate on 2points
		for(Point[] p : list)
		{	
			Point a = p[0];
			Point b = p[1];
			MapPosition nodeA = null;
			MapPosition nodeB = null;
			Utils.disp("------ Treating "+ a.toString()+","+b.toString());

			/* if encoding error (no significant edge), skip */
			if(a.distance(b)<THRESHOLD)
			{
				Utils.disp("edge ~ 0");
				continue;
			}


			/* check if existing or closer */
			for(MapPosition pos: graph.vertexSet())
			{
				Point tempPoint = pos.getPoint();//new Point(pos.getCoordinates()[0], pos.getCoordinates()[1]);
				if(a.distance(tempPoint)<THRESHOLD)
				{
					nodeA = pos;
					Utils.disp("NodeA found");
				}

				if(b.distance(tempPoint)<THRESHOLD)
				{
					nodeB = pos;
					Utils.disp("NodeB found");
				}				

			}

			/* add if new vertex */
			if(nodeA==null)
			{
				Utils.disp("Add nodeA");
				nodeA = new MapPosition(a);//((int) a.getX(), (int) a.getY());
				graph.addVertex(nodeA);
			}

			if(nodeB==null)
			{
				Utils.disp("Add nodeB");
				nodeB = new MapPosition((int) b.getX(), (int) b.getY());
				graph.addVertex(nodeB);
			}

			DefaultWeightedEdge edge = graph.getEdge(nodeA, nodeB);

			/* Not existing in graph*/
			if(edge == null)
			{
				Utils.disp("Non existing edge");
				edge = graph.addEdge(nodeA, nodeB);
				double weight = nodeA.getPoint().distance(nodeB.getPoint());
				Utils.disp("Weight is "+weight);
				graph.setEdgeWeight(edge, weight);
			}		

		}
		
		// Write the final graph
		writeGraph(graph);
		Utils.disp("Graph writed");

		// faire un plot du graphe final (un noeud / 5 sec)
		new graphTester(graph);
	}
	
//	private void generateWeightedSimpleGraph()
//	{
//		SimpleWeightedGraph<MapPosition,DefaultWeightedEdge> graph = new SimpleWeightedGraph<MapPosition,DefaultWeightedEdge>(DefaultWeightedEdge.class);
//		
//		// iterate on 2points
//		for(Point[] p : list)
//		{	
//			Point a = p[0];
//			Point b = p[1];
//			MapPosition nodeA = null;
//			MapPosition nodeB = null;
//			Utils.disp("------ Treating "+ a.toString()+","+b.toString());
//
//			/* if encoding error (no significant edge), skip */
//			if(a.distance(b)<THRESHOLD)
//			{
//				Utils.disp ~ 0");
//				continue;
//			}
//
//
//			/* check if existing or closer */
//			for(MapPosition pos: graph.vertexSet())
//			{
//				Point tempPoint = pos.getPoint();//new Point(pos.getCoordinates()[0], pos.getCoordinates()[1]);
//				if(a.distance(tempPoint)<THRESHOLD)
//				{
//					nodeA = pos;
//					Utils.disp("NodeA found");
//				}
//
//				if(b.distance(tempPoint)<THRESHOLD)
//				{
//					nodeB = pos;
//					Utils.disp("NodeB found");
//				}				
//
//			}
//
//			/* add if new vertex */
//			if(nodeA==null)
//			{
//				Utils.disp("Add nodeA");
//				nodeA = new MapPosition(a);//((int) a.getX(), (int) a.getY());
//				graph.addVertex(nodeA);
//			}
//
//			if(nodeB==null)
//			{
//				Utils.disp("Add nodeB");
//				nodeB = new MapPosition((int) b.getX(), (int) b.getY());
//				graph.addVertex(nodeB);
//			}
//
//			DefaultWeightedEdge edge = graph.getEdge(nodeA, nodeB);
//
//			/* Not existing in graph*/
//			if(edge == null)
//			{
//				disp("Non existing edge");
//				edge = graph.addEdge(nodeA, nodeB);
//				double weight = nodeA.getPoint().distance(nodeB.getPoint());
//				disp("Weight is "+weight);
//				graph.setEdgeWeight(edge, weight);
//			}		
//
//		}
//		
//		// Write the final graph
//		writeGraph(graph);
//		disp("Graph writed");
//
//		// faire un plot du graphe final (un noeud / 5 sec)
//		new graphTester(graph);
//	}

	public static void main(String[] args)
	{
		new PointToGraph();
	}

	private void loadGraph() 
	{
		ObjectInputStream in;

		try 
		{

			in = new ObjectInputStream(new FileInputStream(new File(bin_file_name)));
			list = (ArrayList<Point[]>) in.readObject();
			//correct();
			Utils.disp("Loaded point.bin");
		} 
		catch (FileNotFoundException e) 
		{
			list = new ArrayList<Point[]>();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		} 
		catch (ClassNotFoundException e) 
		{
			e.printStackTrace();
		}

	}

	private void writeGraph(SimpleWeightedGraph<MapPosition, DefaultWeightedEdge> graph) 
	{
		ObjectOutputStream out;
		try 
		{

			out = new ObjectOutputStream(new FileOutputStream(new File(this.graph_bin_filename)));
			out.writeObject(graph); // ouf, serializable
		} 
		catch (FileNotFoundException e1) 
		{
			e1.printStackTrace();
		} 
		catch (IOException e1) 
		{
			e1.printStackTrace();
		}

	}
	private void writeGraph(WeightedPseudograph<MapPosition, DefaultWeightedEdge> graph) 
	{
		ObjectOutputStream out;
		try 
		{

			out = new ObjectOutputStream(new FileOutputStream(new File(this.pseudograph_bin_filename)));
			out.writeObject(graph); // ouf, serializable
		} 
		catch (FileNotFoundException e1) 
		{
			e1.printStackTrace();
		} 
		catch (IOException e1) 
		{
			e1.printStackTrace();
		}

	}
}
